// const str: string = ''
// const bool: boolean = true
// const num: number = 3

// const arr: string[] = ['a', 'b']
// const arr2: Array<string> = ['a', 'b']

// const tuple1: [string, number] = ['a', 3]
// console.log(tuple1[0])

// enum Color {
//   Red = 6,
//   Green = 1,
//   Blue = 2
// }

// // console.log(Color['Red'])
// console.log(Color[6])

// const enum1

// let str: any = true
// str = 0

// let str = 'hello'
// str = 'hello'

// let str: any = 3
// str.abc

// function foo(): void {
  
// }

// function foo(x: number, y: number): number {
//   return x + y
// }

// const foo2 = function(x: number, y: number) {
//   return x + y
// }

// console.log(foo2(100, 200))

// const foo: (x: number, y: number) => number = (x: number, y: number): number => x + y

// foo(100, 200)

// interface Foo {
//   (x: number, y: number): number
// }

// const foo: Foo = (x: number, y: number): number => {
//   return x + y
// }

// const foo = (x: string = 'aaa', y: string = 'bbb') => {
//   return x + y
// }

// console.log(foo())

// function push(array, ...items: Array<any>) {
//   console.log(items)
  
//   items.forEach(function(item) {
//     array.push(item)
//   })
// }

// let a = []
// push(a, 1, 2, 'a')

// const x: string | boolean = 0

// function foo(x) {
//   arguments
// }

// function foo(x, y) {

// }

// function foo(x, y, z) {

// }

// function reverse(x: number): number
// function reverse(x: string): string
// function reverse(x: number | string): number | string {
//   if (typeof x === 'number') {
//     return Number(x.toString().split('').reverse().join(''))
//   } else {
//     return x.split('').reverse().join('')
//   }
// }

// console.log(reverse('156'))



// class Header extends React.component {
//   stata = {
//     x: 0,
//     y: 2
//   }
// }

// interface Person {
//   name: string
//   readonly age?: number
//   [props: string]: any
// }

// const person: Person = {
//   name: 'aaa',
//   gender: 300
// }

// person.age = 300
// person.name = 'abc'

// class Person {
//   protected name: string = ''

//   constructor(name: string) {
//     this.name = name
//   }

//   public talk() {
//     console.log(this.name)
//   }
// }

// class Door {
//   factory: string = ''
// }

// class Student extends Person {
//   constructor(name: string, gender: number) {
//     super(name)
//   }

//   static readonly age: number = 100

//   static sayName() {
//     console.log(this.name)
//   }
  
//   get surname() {
//     return this.name
//   }
  
//   set surname(name: string) {
//     this.name = name
//   }
  
//   learn() {
//     this.talk()
//     console.log(this.name + ' is learning.');
//   }
// }

// let p: Student = new Person('felix')
// p.talk()

// let s: Student = new Student('felix', 100)
// s.surname = 'lu'
// console.log(s.surname)
// Student.sayName()
// Student.age

// s.talk()

// Student.age = 100

// abstract class Person {
//   constructor(public name: string) {
//     this.name = name
//   }

//   talk() {
//     console.log(this.name)
//   }

//   abstract eat(food: string)
// }

// class Student extends Person {
//   eat() {
//     console.log(0);
//   }
// }

// let p = new Student('felix')
// p.eat()

// interface Alerm {
//   alerm()
// }

// interface Fly {
//   flying()
// }

// class Door {
//   width: number = 100
//   height: number = 200
// }

// class SecurityDoor extends Door implements Alerm {
//   color: string = 'red'

//   alerm() {}
// }

// class Car implements Alerm, Fly {
//   alerm() {}
//   flying() {}
// }

// interface Alarm {
//   alert()
// }

// interface LightableAlarm extends Alarm {
//   lightOn()
//   lightOff()
// }

// class Car implements LightableAlarm {
//   lightOff() {}
//   lightOn() {}
//   alert() {}
// }

// class Point {
//   x: number = 100
//   y: number = 200
// }

// interface Point3d extends Point {
//   z: number
// }

// // let point3d: Point3d = {x: 1, y: 2, z: 3}

// class Point4d implements Point3d {
//   z = 100
//   x = 200
//   y = 300
// }

// interface SearchFunc {
//   x: string
//   foo: (source: string, subString: string) => boolean
// }

// let mySearch: SearchFunc
// mySearch = function(source: string, subString: string): boolean {
//   return source.search(subString) !== -1
// }

// let sf: SearchFunc = {
//   x: 'hello',
//   foo: (source: string, subString: string): boolean => {
//     return true
//   }
// }

// console.log(sf.x)
// console.log(sf.foo('a', 'b'))

// function createArray(length: number, value: any): Array<any> {
//   let result = []
//   for (let i = 0; i < length; i++) {
//     result[i] = value.toString()
//   }
//   return result
// }

// console.log(createArray(3, 100)) // ['x', 'x', 'x']

// function createArray<A>(length: number, value: A): Array<A> {
//   let result: Array<A> = []
//   for (let i = 0; i < length; i++) {
//     result[i] = value
//   }
//   return result
// }

// console.log(createArray(3, 100)) // ['x', 'x', 'x']
// console.log(createArray(3, 'x')) // ['x', 'x', 'x']

// function swap<T, U>(tuple: [T, U]): [U, T] {
//   return [tuple[1], tuple[0]]
// }

// swap<number, string>([7, 'seven']) // ['seven', 7]

// interface Lengthwise {
//   length: number
// }

// function loggingIdentity<T extends Lengthwise>(arg: T): T {
//   console.log(arg.length)
//   return arg
// }

// loggingIdentity<string>('abc')

// interface CreateArrayFunc {
//   <T>(length: number, value: T): Array<T>
// }

// let createArray: CreateArrayFunc;
// createArray = function<T>(length: number, value: T): Array<T> {
//   let result: T[] = []
//   for (let i = 0; i < length; i++) {
//     result[i] = value
//   }
//   return result
// }

// interface State {
//   name: string
// }

// class Header extends React.Component<Props, State> {
//   state: State = {
//     name: 'abc'
//   }
// }

// interface Class {
//   new(...args: any[]): {}
// }

// function desc<T extends Class>(target: T) {
//   console.log(target)

//   return class extends target {
//     name = 'abc'
//     gender = '男'
//     say() {
//       console.log(this.gender, this.name)
//     }
//   }
// }
// interface Class {
//   $surname: string
// }

// function desc(args: string) {
//   return function<T extends Class>(target: T) {
//     console.log(args)
//     target.prototype.$surname = 'abc'
//   }
// }

// @desc('hello')
// class Person {
//   public name: string | undefined
//   public age: number | 0

//   constructor(name, age) {
//     this.name = name
//     this.age = age
//   }

//   say() {
//     console.log(this.name, this.age)
//   }
// }

// let p = new Person('Felix', 20)
// // p.say()
// console.log(p.$surname)


// interface Class {
//   new(...rest: any[]): {}
// }

// function desc<T extends Class>(Target: T) {
//   return class extends Target {
//     gender = '男'
//     say() {
//       console.log(this.gender)
//     }
//   }
// }

// @desc
// class Person {
//   public name: string | undefined
//   public age: number | 0

//   constructor(name, age) {
//     this.name = name
//     this.age = age
//   }

//   say() {
//     console.log(this.name, this.age)
//   }
// }

// let p = new Person('Felix', 20)
// console.log(p)
// p.say()



// function desc(params: string) {
//   // return function (target) {
//   //   // console.log('params', params)
//   //   // console.log('target', target)
//   //   // 直接在原型上扩展一个属性
//   //   // target.prototype.apiUrl = params
//   //   apiUrl = 'hello'
//   // }
//   return function(target) {
//     return class P2 extends target {
//       apiUrl = 'aaa'
//     }
//   }
// }

// @desc('好程序员')
// class P {
//   public apiUrl: string
//   constructor() {
//     this.apiUrl = 'abc'
//   }
//   say() {
//     console.log('说话')
//   }
// }

// const p = new P()
// console.log(p.apiUrl)


// function desc(target) {
//   return class extends target{
//     name = 'Felixlu'
//     age = 18
//     sayHell() {
//       console.log('我是重载后的', this.name)
//     }
//   }
// }

// @desc
// class Person {
//   public name: string | undefined
//   public age: number | 0

//   constructor() {
//     this.name = 'Felix'
//     this.age = 20
//   }

//   sayHell() {
//     console.log('hello word', this.name)
//   }
// }

// let p = new Person()
// console.log(p)
// p.sayHell()



// function desc(params: string) {
//   return function (target: Function) {
//     console.log('params', params)
//     console.log('target', target)
//     // 直接在原型上扩展一个属性
//     target.prototype.apiUrl
//   }
// }

// @desc('好程序员')
// class P {
//   say() {
//     console.log('说话')
//   }
// }

// let p: P = new P()
// console.log(p.apiUrl)

// function desc(target, key, descriptor) {
//   // target.apiUrl = 'abc'
//   // target.foo = () => {
//   //   console.log(0)
//   // }
//   // descriptor.value = () => {
//   //   console.log(0)
//   // }
//   // target.say = () => {
//   //   console.log(0)
//   // }
//   let say = descriptor.value
//   descriptor.value = () => {
//     say()
//     console.log(0)
//   }
// }

// function desc(target, key, index) {
//   target[key]('a')
// }

// class Person {
//   // @desc
//   public name: string | undefined
//   public age: number | 0

//   constructor(name, age) {
//     this.name = name
//     this.age = age
//   }

//   greet(@desc str: string, str2: string) {
//     console.log(str);
//   }

//   // @desc
//   say() {
//     console.log('说的方法')
//   }
// }

// let p = new Person('abc', 100) 
// // p.foo()
// console.log(p.name)
// // console.log(p.gender)

function logCls(params: string) {
  return function (target: any) {
    console.log('4.类的装饰器');
  }
}

function logMethod(params: string) {
  return function (target: any, key: string, descriptor: {[propsName: string]: any}) {
    console.log('3.类的函数装饰器');
  }
}

function logParams(params: string) {
  return function (target: any, name: string) {
    console.log('1.类属性装饰器');
  }
}

function logQuery(params: string) {
  return function (target: any, key: string, index: number) {
    console.log('2.函数参数装饰器');
  }
}

@logCls('类的装饰器')
class Person{
  @logParams('属性装饰器')
  public name: string | undefined;

  @logMethod('函数装饰器')
  getData(@logQuery('函数参数装饰器') age: number, @logQuery('函数参数装饰器') gender: string) {
    console.log('----');
  }
}